/*
 * Copyright 2007-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.paoding.rose.web.impl.module;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.paoding.rose.web.ControllerErrorHandler;
import net.paoding.rose.web.ControllerInterceptor;
import net.paoding.rose.web.annotation.DefaultController;
import net.paoding.rose.web.annotation.ReqMethod;
import net.paoding.rose.web.impl.mapping.Mapping;
import net.paoding.rose.web.impl.mapping.MappingFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartResolver;

/**
 * {@link Module}的实现
 * 
 * @author qieqie.wang@paoding.net
 * 
 */
public class ModuleBean implements Module {

	private static Log logger = LogFactory.getLog(ModuleBean.class);

	// 该模块的地址，由name自动计算而来
	private String path;
	private String[] pathElements;

	// 本module下的controller以及附属信息
	private List<Mapping<Controller>> controllerMappings = new ArrayList<Mapping<Controller>>();
	
	// 用于add方法加进来，最终==>到下面的interceptors
	private ArrayList<NamedControllerInterceptor> interceptorList;

	// 该模块的拦截器，调用get方法时候，由interceptorList.toArray进来,返回时保证非null
	private NamedControllerInterceptor[] interceptors;

	// 本模块的ErrorHanlder
	private ControllerErrorHandler errorHandler;

	// 默认的控制器，会先看看有没有@Path("")标注的或@DefaultController标注的，
	// 没有的话则按照候选方案看看有没有default,index,home,welcome的控制器，有的话就是它了
	private Mapping<Controller> defaultController;
	private boolean defaultControllerCached;

	//
	private MultipartResolver multipartResolver;

	public ModuleBean() {
	}

	public ModuleBean(String path) {
		this.path = path;
		if (path.length() == 0) {
			this.pathElements = new String[0];
		} else {
			this.pathElements = path.substring(1).split("/|\\.");
		}
	}

	@Override
	public String getPath() {
		return path;
	}

	@Override
	public Mapping<Controller> getDefaultController() {
		if (!defaultControllerCached) {
			if (defaultController == null) {
				for (Mapping<Controller> info : controllerMappings) {
					if ("".equals(info.getPath())) {
						defaultController = info;
						break;
					}
				}
			}
			if (defaultController == null) {
				for (Mapping<Controller> info : controllerMappings) {
					if (info.getMappingTarget().getControllerClass().getAnnotation(DefaultController.class) != null) {
						defaultController = info;
						logger.info("module '" + getPath()
								+ "': found default controller '"
								+ defaultController + "'("
								+ info.getMappingTarget().getControllerClass().getName()
								+ ") by annotation @"
								+ DefaultController.class.getSimpleName());
						break;
					}
				}
			}
			if (defaultController == null) {
				String[] candidates = { "/default", "/index", "/home",
						"/welcome", "/hello" };
				for (String candidate : candidates) {
					for (Mapping<Controller> info : controllerMappings) {
						if (candidate.equals(info.getPath())) {
							defaultController = info;
							logger.info("module '"
								+ getPath()
								+ "': found default controller '"
								+ defaultController
								+ "'("
								+ info.getMappingTarget().getControllerClass().getName()
								+ ")  by sacnning controller by convention.");
							break;
						}
						
					}
				}
			}
			if (defaultController == null) {
				if (logger.isWarnEnabled()) {
					logger.warn("module '" + getPath() + "': nout found"
							+ " a default controller by annotation"
							+ " or by convention.");
				}
			}
			defaultControllerCached = true;
		}
		return defaultController;
	}

	public void setDefaultController(Mapping<Controller> defaultController) {
		this.defaultController = defaultController;
	}
	
	@Override
	public List<Mapping<Controller>> getControllerMappings() {
		List<Mapping<Controller>> controllerInfos = new ArrayList<Mapping<Controller>>(this.controllerMappings.size());
		controllerInfos.addAll(this.controllerMappings);
		Collections.sort(controllerInfos);
		return Collections.unmodifiableList(controllerInfos);
	}
	
	public ModuleBean addController(String controllerPath,
			ReqMethod[] methods, Class<?> controllerClass, Object controller) {
		Controller contr = new Controller();
		contr.setControllerClass(controllerClass);
		contr.setControllerObject(controller);
		this.controllerMappings.add(MappingFactory.createMapping(
				controllerPath, MappingFactory.MODE_STARTS_WITH, methods, contr));
		return this;
	}

	public ModuleBean addControllerInterceptor(String name,
			ControllerInterceptor interceptor) {
		NamedControllerInterceptor namedInterceptor = new NamedControllerInterceptor(
				name, interceptor);
		return addNamedControllerInterceptor(namedInterceptor);
	}

	public ModuleBean addNamedControllerInterceptor(
			NamedControllerInterceptor namedInterceptor) {
		if (interceptorList == null) {
			interceptorList = new ArrayList<NamedControllerInterceptor>();
		}
		for (int i = 0; i < interceptorList.size(); i++) {
			if (namedInterceptor.getPriority() > interceptorList.get(i)
					.getPriority()) {
				this.interceptorList.add(i, namedInterceptor);
				return this;
			}
		}
		this.interceptorList.add(namedInterceptor);
		interceptors = null;
		return this;
	}

	@Override
	public NamedControllerInterceptor[] getInterceptors() {
		if (interceptors == null) {
			if (interceptorList == null) {
				interceptors = new NamedControllerInterceptor[0];
			} else {
				interceptors = interceptorList
						.toArray(new NamedControllerInterceptor[interceptorList
								.size()]);
			}
		}
		return interceptors;
	}

	@Override
	public ControllerErrorHandler getErrorHandler() {
		return errorHandler;
	}

	public void setErrorHandler(ControllerErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	@Override
	public MultipartResolver getMultipartResolver() {
		return multipartResolver;
	}

	public void setMultipartResolver(MultipartResolver multipartResolver) {
		this.multipartResolver = multipartResolver;
	}

	@Override
	public int compareTo(Module o) {
		if (this == o) {
			return 0;
		}
		if (path.length() == 0) {
			return 1;
		}
		ModuleBean that = ((ModuleBean) o);
		if (pathElements.length > that.pathElements.length) {
			return -1;
		} else if (pathElements.length < that.pathElements.length) {
			return 1;
		} else {
			for (int i = 0; i < pathElements.length; i++) {
				String pathElement = pathElements[i];
				String thatPathElement = that.pathElements[i];
				if (pathElement.startsWith(thatPathElement)) {
					return -1;
				}
				if (thatPathElement.startsWith(pathElement)) {
					return 1;
				}
				return pathElement.length() - thatPathElement.length();
			}
		}
		return 0;
	}
}
